package com.siebre.picclife.asynctask.springconfig;

import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.integration.core.MessagingOperations;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import com.siebre.picclife.asynctask.service.TaskManager;
import com.siebre.picclife.asynctask.service.TaskProcessor;
import com.siebre.picclife.asynctask.service.TaskRecoverer;
import com.siebre.picclife.asynctask.service.TaskRepository;
import com.siebre.picclife.asynctask.service.TaskService;
import com.siebre.picclife.asynctask.service.support.ArgumentDeserializerResolver;
import com.siebre.picclife.asynctask.service.support.DefaultTaskManager;
import com.siebre.picclife.asynctask.service.support.DefaultTaskRecoverer;
import com.siebre.picclife.asynctask.service.support.DefaultTaskService;
import com.siebre.picclife.asynctask.service.support.MethodInvokingTaskProcessor;
import com.siebre.picclife.asynctask.service.support.TaskHandlerRegistrar;
import com.siebre.picclife.asynctask.service.support.DefaultTaskRecoverer.TaskServiceIdManager;
import com.siebre.picclife.asynctask.springcontext.TaskProcessingBootstrap;

@Configuration
@Import({TaskArgumentHandlerConfig.class, TaskRepositoryConfig.class, SpringIntegrationInfrastructureConfig.class})
@ImportResource("classpath:spring/integration/task-processing.xml")
public class TaskProcessConfig {
	
	private Logger logger = LoggerFactory.getLogger(TaskProcessConfig.class);
	
	private static final String BOOTSTRAP_PROP = "asynctask.process.bootstrap.auto";
	
	@Autowired(required = false)
	private List<TaskHandlerRegistrar> taskHandlerRegistrars = Collections.emptyList();
	
	@Bean
	TaskProcessingBootstrap taskProcessingBootstrap(TaskManager taskManager, TaskRecoverer taskRecoverer,
			@Value("${" + BOOTSTRAP_PROP + ":true}") boolean auto) {
		logger.info("{}:{}", BOOTSTRAP_PROP, auto);
		return new TaskProcessingBootstrap(taskManager, taskRecoverer, auto);
	}
	
	@Bean
	TaskRecoverer taskRecoverer(TaskServiceIdManager idManager, TaskService taskService) {
		return new DefaultTaskRecoverer(idManager, taskService);
	}
	
	@Bean
	TaskManager taskManager(MessagingOperations messagingOps) {
		return new DefaultTaskManager(messagingOps);
	}
	
	@Bean
	TaskServiceIdManager taskServiceIdManager(@Value("${asynctask.serviceId.persist.path:target/task-service-id}") String path) {
		return new TaskServiceIdManager(path);
	}
	
	@Bean
	TaskService taskService(
			TaskRepository repository,
			@Value("${asynctask.restarter.maxRetryCount:5}") int maxRetryCount) {
		DefaultTaskService result = new DefaultTaskService(repository);
		result.setMaxRetryCount(maxRetryCount);
		return result;
	}
	
	@Bean
	TaskProcessor taskProcessor(
			ArgumentDeserializerResolver deserializerResolver,
			PlatformTransactionManager transactionManager,
			TaskService taskService) {
		MethodInvokingTaskProcessor result = new MethodInvokingTaskProcessor(
				deserializerResolver, new TransactionTemplate(transactionManager), taskService);
		for (TaskHandlerRegistrar taskHandlerRegistrar : taskHandlerRegistrars) {
			taskHandlerRegistrar.register(result);
		}
		return result;
	}
}